/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.web.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.comac.ins.common.core.constant.UserConstants;
import com.comac.ins.common.core.domain.R;
import com.comac.ins.common.core.domain.model.LoginBody;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MessageUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.core.utils.ValidatorUtils;
import com.comac.ins.common.encrypt.annotation.ApiEncrypt;
import com.comac.ins.common.json.utils.JsonUtils;
import com.comac.ins.common.satoken.utils.LoginHelper;
import com.comac.ins.common.security.domain.SsoEmployeeInfo;
import com.comac.ins.common.security.utils.CookieUtil;
import com.comac.ins.common.websocket.dto.WebSocketMessageDto;
import com.comac.ins.common.websocket.utils.WebSocketUtils;
import com.comac.ins.system.domain.vo.SysClientVo;
import com.comac.ins.system.domain.vo.SysUserVo;
import com.comac.ins.system.service.ISysClientService;
import com.comac.ins.web.domain.vo.LoginVo;
import com.comac.ins.web.service.IAuthStrategy;
import com.comac.ins.web.service.SysLoginService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 统一认证入口
 *
 * @author hxloongs
 */
@Slf4j
@SaIgnore
@RequiredArgsConstructor
@RestController
@RequestMapping("/isfd/sso")
public class IsfdController {

    private final SysLoginService loginService;
    private final ISysClientService clientService;
    private final ScheduledExecutorService scheduledExecutorService;

    @Value("${sso.header}")
    private String ssoHeader;

    @Value("${sso.auth.header}")
    private String ssoAuthHeader;

    @Value("${sso.auth.url}")
    private String ssoAuthUrl;

    @Value("#{T(java.lang.Boolean).parseBoolean('${sso.enable}')}")
    private Boolean ssoEnable;

    @Value("${isfd.nopassword.clientId}")
    private String clientId;

    @Autowired
    private RestTemplate tokenRestTemplate;

    /**
     * 统一认证免密登录
     *
     * @return 结果
     */
    @ApiEncrypt
    @GetMapping("/login")
    public R<LoginVo> login(HttpServletRequest request) {
        log.info("isfd 免密登录开始");

        // 1. 获取统一认证sessionId
        String cookieSessionId = getSsoSessionId(request);
        if (StringUtils.isEmpty(cookieSessionId)) {
            log.error("SSO sessionId获取失败");
            throw new BaseException("认证信息缺失，请重新登录");
        }

        // 2. 调用认证中心获取用户信息
        log.info("调用认证中心获取用户信息");
        SsoEmployeeInfo ssoEmployeeInfo = getSsoUserFromAuthCenter(cookieSessionId);
        log.info("SSO用户信息: {}", JsonUtils.toJsonString(ssoEmployeeInfo));
        String employeeCode = ssoEmployeeInfo.getEmployeeCode();
        // 3. 完成要素库的免密登录
//        String employeeCode = "500695";
        SysUserVo sysUserVo = loginService.getUserByUserName(employeeCode);
        if (sysUserVo == null) {
            throw new BaseException("业务系统用户不存在，请关联用户后重试！");
        }
        JSONObject loginBodyJson = new JSONObject();
        loginBodyJson.set("tenantId", sysUserVo.getTenantId());
        loginBodyJson.set("username", sysUserVo.getUserName());
        // loginBodyJson.set("password",sysUserVo.getUserName());
        loginBodyJson.set("rememberMe", Boolean.TRUE);
        loginBodyJson.set("clientId", clientId);
        loginBodyJson.set("grantType", "nopassword");
        String loginBodyJsonStr = loginBodyJson.toString();
        LoginBody loginBody = JsonUtils.parseObject(loginBodyJsonStr, LoginBody.class);

        ValidatorUtils.validate(loginBody);
        // 授权类型和客户端id
        String clientId = loginBody.getClientId();
        String grantType = loginBody.getGrantType();
        SysClientVo client = clientService.queryByClientId(clientId);
        // 查询不到 client 或 client 内不包含 grantType
        if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
            log.info("客户端id: {} 认证类型：{} 异常!.", clientId, grantType);
            return R.fail(MessageUtils.message("auth.grant.type.error"));
        } else if (!UserConstants.NORMAL.equals(client.getStatus())) {
            return R.fail(MessageUtils.message("auth.grant.type.blocked"));
        }
        // 校验租户
        loginService.checkTenant(loginBody.getTenantId());
        // 登录
        LoginVo loginVo = IAuthStrategy.login(loginBodyJsonStr, client, grantType);

        Long userId = LoginHelper.getUserId();
        scheduledExecutorService.schedule(() -> {
            WebSocketMessageDto dto = new WebSocketMessageDto();
            dto.setMessage("欢迎登录Comac-ins后台管理系统");
            dto.setSessionKeys(List.of(userId));
            WebSocketUtils.publishMessage(dto);
        }, 3, TimeUnit.SECONDS);
        return R.ok(loginVo);
    }


    /**
     * 从请求中获取SSO SessionID
     */
    public String getSsoSessionId(HttpServletRequest request) {
        String ssoTicket = CookieUtil.getValue(request, ssoHeader);
        if (StringUtils.isBlank(ssoTicket)) {
            ssoTicket = request.getParameter(ssoHeader);
        }
        if (StringUtils.isBlank(ssoTicket)) {
            ssoTicket = request.getHeader(ssoHeader);
        }
        return ssoTicket;
    }

    /**
     * 从认证中心获取用户信息
     */
    public SsoEmployeeInfo getSsoUserFromAuthCenter(String ssoTicket) {
        if (StringUtils.isEmpty(ssoTicket)) {
            throw new BaseException("无效的SSO认证标识");
        }

        log.info("SSO Ticket {} 获取单点登录认证用户信息", ssoTicket);
        HttpHeaders headers = new HttpHeaders();
        headers.set(ssoAuthHeader, ssoTicket);
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(headers);

        log.info("请求认证中心{} 获取用户信息", ssoAuthUrl);
        ResponseEntity<JSONObject> response = tokenRestTemplate.postForEntity(ssoAuthUrl, entity, JSONObject.class);

        JSONObject body = response.getBody();
        if (ObjectUtils.isEmpty(body) || body.getInt("code") != 0) {
            throw new BaseException("认证中心服务异常");
        }

        JSONObject data = body.getJSONObject("data");
        if (data == null) {
            throw new BaseException("用户信息获取失败");
        }
        return JsonUtils.parseObject(data.toString(), SsoEmployeeInfo.class);
    }
}
